package gui;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

import javax.swing.DefaultListModel;
import javax.swing.JList;

import sfg.Solver;
import dataStructure.Graph.G_Path;
import dataStructure.Path;
import fn.Function;

public class ToolEvaluate extends Tool {

	private boolean input, output;
	private UI_Node n;
	private UI_Node inN, outN;
	private ArrayList<Path<UI_Node>> path;
	private ArrayList<Path<UI_Node>> fwd;
	private ArrayList<Path<UI_Node>> loop;
	private ArrayList<ArrayList<ArrayList<Path<UI_Node>>>> nonTouch;
	private Solver<UI_Node, UI_Branch> s;

	@Override
	public void select(MainFrame f) {
		f.status("Evaluate tool selected...");
		clear(f, null);
	}

	@Override
	public void keyType(MainFrame thisFrame, UI_SFG graph, KeyEvent e, boolean done) {}

	@Override
	public void mouseClick(MainFrame f, UI_SFG graph, MouseEvent e, MyView v) {
		if (input)
			input = false;
		else if (output)
			output = false;
	}

	@Override
	public void mouseMove(MainFrame f, UI_SFG graph, MouseEvent e, int dX, int dY, MyView v) {
		n = snap(f, graph, new Point(e.getX(), e.getY()), null);
		if (input && n != outN)
			inN = n;
		else if (output && n != inN)
			outN = n;
	}

	@Override
	public void mouseDrag(MainFrame f, UI_SFG graph, MouseEvent e, int dX, int dY, MyView v) {
		mouseMove(f, graph, e, dX, dY, v);
	}

	@Override
	public Cursor cursor() {
		if (n != null && (input || output))
			return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
		else
			return Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
	}

	@Override
	public void paint(MainFrame mainFrame, UI_SFG graph, Graphics2D g, MyView v) {
		g.setColor(Color.GREEN);
		if (inN != null)
			inN.paint(g, v);
		g.setColor(Color.RED);
		if (outN != null)
			outN.paint(g, v);
		if (path != null)
			for (Path<UI_Node> p : path)
				draw(p, graph, g, v);
	}

	@Override
	public boolean isBusy() {
		return false;
	}

	@Override
	public void clear(MainFrame f, UI_SFG graph) {
		s = null;
		n = null;
		inN = null;
		outN = null;
		input = false;
		output = false;
	}

	public void input(MainFrame thisFrame, UI_SFG ui_SFG) {
		inN = null;
		input = true;
		output = false;
	}

	public void output(MainFrame thisFrame, UI_SFG ui_SFG) {
		outN = null;
		input = false;
		output = true;
	}

	private void draw(Path<UI_Node> p, UI_SFG graph, Graphics2D g, MyView v) {
		int j = p.start();
		for (Integer i : p.path()) {
			g.setColor(Color.CYAN);
			graph.getConnection(j, j = i).paint(g, v);
		}
	}

	public void evaluate(MainFrame f, UI_SFG graph, JList<ArrayList<Path<UI_Node>>> lstPath, JList lstDtrm) {
		int i;
		s = Solver.<UI_Node, UI_Branch> get(graph, inN, outN);
		// PATHS
		DefaultListModel mdl = new DefaultListModel();
		i = 0;
		fwd = s.forwardPaths();
		for (Path<UI_Node> p : fwd)
			mdl.addElement(((G_Path) p).setName("M" + ++i));
		i = 0;
		loop = s.loops();
		for (Path<UI_Node> p : loop)
			mdl.addElement(p);
		nonTouch = s.nonTouchingLoop();
		for (ArrayList<ArrayList<Path<UI_Node>>> gp : nonTouch)
			for (ArrayList<Path<UI_Node>> set : gp)
				mdl.addElement(set);
		f.lstPath.setModel(mdl);
		f.lstPath.repaint();
		// DTRMS
		DefaultListModel mdlD = new DefaultListModel();
		mdlD.addElement(s.transferFunction().setName("TF"));
		mdlD.addElement(s.delta().setName("D"));
		i = 0;
		for (Function d : s.deltas())
			mdlD.addElement(d.setName("D" + ++i));
		f.lstDtrm.setModel(mdlD);
		f.lstDtrm.repaint();
	}

	public void selectPath(MainFrame f, UI_SFG graph, int sel) {
		if (sel < 0)
			return;
		path = new ArrayList();
		Object p = f.lstPath.getModel().getElementAt(sel);
		if (p instanceof ArrayList) {
			path.addAll((Collection) p);
			f.panelFunction.setFn(s.evaluatePath((Collection) p));
		} else if (p instanceof Path) {
			path.add((Path) p);
			f.panelFunction.setFn(s.evaluatePath((Path) p));
		}
	}

	public void selectDtrm(MainFrame f, UI_SFG graph, int sel) {
		if (sel < 0)
			return;
		f.panelFunction.setFn(f.lstDtrm.getModel().getElementAt(sel));
	}

}
